/**
 * JWT认证中间件模块
 * 
 * 主要功能：
 * 1. 生成JWT Token（用于用户登录后的身份认证）
 * 2. 验证JWT Token（保护需要认证的API路由）
 * 
 * JWT (JSON Web Token)工作原理：
 * - 用户登录成功后，服务器生成一个包含用户信息的Token
 * - Token由三部分组成：Header.Payload.Signature
 * - 客户端在后续请求中携带Token（通常放在Authorization头中）
 * - 服务器验证Token的签名和有效期，确认用户身份
 * 
 * 优点：
 * - 无状态：服务器不需要存储session，易于扩展
 * - 跨域友好：可以跨不同域名使用
 * - 移动端友好：不依赖cookie
 * 
 * @author 个人预算管理系统开发团队
 * @date 2025-10-26
 */

// ==================== 依赖导入 ====================
const jwt = require('jsonwebtoken'); // JSON Web Token库

// ==================== 配置常量 ====================

/**
 * JWT密钥
 * 用于签名和验证Token的密钥
 * 
 * 安全提示：
 * 1. 生产环境必须设置环境变量JWT_SECRET
 * 2. 密钥应该是复杂的随机字符串（至少32位）
 * 3. 不要将密钥提交到代码仓库
 */
const JWT_SECRET = process.env.JWT_SECRET || 'your_secret_key';

// ==================== Token生成函数 ====================

/**
 * 生成JWT Token
 * 
 * @function generateToken
 * @description 根据用户信息生成一个JWT Token，用于后续的身份认证
 * 
 * @param {object} user - 用户对象
 * @param {number} user.user_id - 用户ID
 * @param {string} user.username - 用户名
 * @param {string} user.email - 用户邮箱
 * 
 * @returns {string} JWT Token字符串
 * 
 * @example
 * const token = generateToken({
 *   user_id: 1,
 *   username: 'zhangsan',
 *   email: 'zhangsan@example.com'
 * });
 * // 返回: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
 * 
 * 设计思路：
 * 1. Payload中只包含必要的用户信息（不包含敏感信息如密码）
 * 2. 使用环境变量配置过期时间，默认7天
 * 3. 使用HS256算法进行签名（对称加密）
 * 
 * 安全考虑：
 * - 不在Payload中存储密码、敏感信息
 * - Payload是Base64编码，可以被解码，不是加密
 * - 只有签名部分是加密的，保证Token未被篡改
 */
function generateToken(user) {
    // 构造Token的Payload（负载）
    // Payload包含用户的基本信息，用于后续验证身份
    const payload = {
        user_id: user.user_id,     // 用户ID：唯一标识
        username: user.username,   // 用户名：显示用
        email: user.email          // 邮箱：联系方式
    };
    
    // 使用jwt.sign()生成Token
    // 参数1：payload - 要编码的数据
    // 参数2：secret - 密钥
    // 参数3：options - 选项（如过期时间）
    return jwt.sign(payload, JWT_SECRET, {
        expiresIn: process.env.JWT_EXPIRES_IN || '7d'  // Token有效期：默认7天
    });
}

// ==================== Token验证中间件 ====================

/**
 * JWT Token验证中间件
 * 
 * @function authenticateToken
 * @description Express中间件，验证请求头中的JWT Token，保护需要认证的路由
 * 
 * @param {object} req - Express请求对象
 * @param {object} res - Express响应对象
 * @param {function} next - Express next函数，调用下一个中间件
 * 
 * @returns {void}
 * 
 * @example
 * // 在路由中使用
 * router.get('/protected', authenticateToken, (req, res) => {
 *   // req.user 包含解码后的用户信息
 *   res.json({ user: req.user });
 * });
 * 
 * 工作流程：
 * 1. 从请求头Authorization中提取Token
 * 2. 验证Token的签名和有效期
 * 3. 如果验证成功，将用户信息附加到req.user
 * 4. 如果验证失败，返回401或403错误
 * 
 * Token格式：
 * Authorization: Bearer <token>
 * 
 * 错误处理：
 * - 401 未授权：Token缺失或已过期
 * - 403 禁止访问：Token无效（被篡改）
 */
function authenticateToken(req, res, next) {
    // 1. 从请求头获取Authorization字段
    // 格式：Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
    const authHeader = req.headers['authorization'];
    
    // 2. 提取Token（去掉"Bearer "前缀）
    // split(' ') 将字符串分割为数组：['Bearer', 'token']
    // [1] 取第二个元素（即token部分）
    const token = authHeader && authHeader.split(' ')[1];
    
    // 3. 检查Token是否存在
    if (!token) {
        // Token不存在，返回401未授权错误
        return res.status(401).json({ 
            code: 401, 
            message: '未授权：缺少Token' 
        });
    }
    
    // 4. 验证Token
    // jwt.verify() 是异步验证函数，使用回调处理结果
    jwt.verify(token, JWT_SECRET, (err, decoded) => {
        // 如果验证失败，err包含错误信息
        if (err) {
            // 4.1 检查是否是Token过期错误
            if (err.name === 'TokenExpiredError') {
                return res.status(401).json({ 
                    code: 401, 
                    message: 'Token已过期，请重新登录' 
                });
            }
            
            // 4.2 其他错误（如签名无效、格式错误等）
            return res.status(403).json({ 
                code: 403, 
                message: 'Token无效' 
            });
        }
        
        // 5. 验证成功
        // decoded 包含解码后的Payload（用户信息）
        // 将用户信息附加到req对象，供后续路由处理函数使用
        req.user = decoded;
        
        // 6. 调用next()，继续执行下一个中间件或路由处理函数
        next();
    });
}

// ==================== 导出模块 ====================

/**
 * 导出认证相关函数
 * 
 * @exports generateToken - Token生成函数
 * @exports authenticateToken - Token验证中间件
 */
module.exports = {
    generateToken,      // 用于登录时生成Token
    authenticateToken   // 用于保护需要认证的路由
}; 